/******************************************************************************
 *
 * Copyright:
 *    (C) 2005 Embedded Artists AB
 *
 * File:
 *    uart.c
 *
 * Description:
 *    Implementation of polled mode for UART #0.
 *
 *****************************************************************************/

/******************************************************************************
 * Includes
 *****************************************************************************/
#include "../Startup/general.h"
#include "../Startup/lpc2xxx.h"
#include "lcd_hw.h"
#include "lcd.h"
#include "uart.h"
#include "utils.h"


void initUart0(tU16 div_factor, tU8 mode, tU8 fifo_mode)
{
  volatile tU32 dummy;
  
  //enable uart #0 pins in GPIO (P0.0 = TxD0, P0.1 = RxD0)
  PINSEL0 = (PINSEL0 & 0xfffffff0) | 0x00000005;

  U0IER = 0x00;                        //disable all uart interrupts
  dummy = U0IIR;                       //clear all pending interrupts
  dummy = U0RBR;                       //clear receive register
  dummy = U0LSR;                       //clear line status register

  //set the bit rate = set uart clock (pclk) divisionfactor
  U0LCR = 0x80;                        //enable divisor latches (DLAB bit set, bit 7)
  U0DLL = (tU8)div_factor;             //write division factor LSB
  U0DLM = (tU8)(div_factor >> 8);      //write division factor MSB

  //set transmissiion and fifo mode
  U0LCR = (mode & ~0x80);              //DLAB bit (bit 7) must be reset
  U0FCR = fifo_mode;

  Uart0ClrFifo();
  Sleep(100);
}


void uart0SendChar(tU8 charToSend)
{
  //Wait until THR (Transmit Holding Register) is empty = THRE bit gets set
  while(!(U0LSR & 0x20))
    ;
  U0THR = charToSend;
}


void uart0SendCh(tU8 charToSend)
{
  /*if(charToSend == '\n')
    uart0SendChar('\r');*/

  uart0SendChar(charToSend);
}


void uart0SendString(tU8 *pString)
{
  while(*pString)
    uart0SendCh(*pString++);
}


void uart0SendChars(char *pBuff, tU16 count)
{
  while (count--)
    uart0SendChar(*pBuff++);
}


tU8 uart0TxEmpty(void)
{
  //return TRUE if both THRE and TEMT bits are set
  //THRE = Transmitter Holding Register Empty (0x20)
  //TEMT = Transmitter Empty (0x40)
  return ((U0LSR & 0x60) == 0x60);
}


void uart0TxFlush(void)
{
  //clear/reset the tx fifo
  U0FCR |= 0x04;
}

tU8 uart0GetCh(void)
{
  //wait for Received Data Ready bit (0x01) to be set 
  while(!(U0LSR & 0x01))
    ;
  lcdClrscr();
  lcdPuts("getch");
  return U0RBR;
}


tU8 uart0GetChar(/*tU8 *pRxChar*/)
{
  //check if Received Data Ready bit (0x01) to be set 
  /*if((U0LSR & 0x01) != 0x00)
  {
    *pRxChar = U0RBR;
    return TRUE;
  }
  return FALSE;*/

	while(!(U0LSR & 0x01));
	return U0RBR;
}

void Uart0ClrFifo()
{
	U0FCR = U0FCR & 0x06;
	Sleep(100);
}

void uart0SendBuffer(tU8* pBuff, tU16 count)
{
  while (count--)
    uart0SendChar(*pBuff++);
}

void uart0SetPinsel()
{
	PINSEL0 = (PINSEL0 & 0xfffffff0) | 0x00000005;
}

void initUart0_96008N1_FifoOff()
{
	volatile tU32 dummy;
	tU16 divFactor = ((CRYSTAL_FREQUENCY * PLL_FACTOR) / VPBDIV_FACTOR) / (16 * 9600);

	  //ustawienie pinsel
	  PINSEL0 = (PINSEL0 & 0xfffffff0) | 0x00000005;

	  //wylaczenie przerwan i wyzerowanie rejestrow
	  U0IER = 0x00;
	  dummy = U0IIR;
	  dummy = U0RBR;
	  dummy = U0LSR;

	  //ustawienie wspolczynnika pozialu
	  U0LCR = 0x80;                        //enable divisor latches (DLAB bit set, bit 7)
	  U0DLL = (tU8)divFactor;             //write division factor LSB
	  U0DLM = (tU8)(divFactor >> 8);      //write division factor MSB

	  U0LCR = 1 | 1 << 1 ; // zerowanie dlab, 9600, no parity, 1 bit stopu
	  U0FCR = 0x00;

	  Uart0ClrFifo();
	  Sleep(100);
}

tBool XmSendData(tU8* data, tU32 bytes)
{
	tU8 failedRetry = 0;
	tU16 finalPacketSize;
	tBool initalized = FALSE;
	int i;
	//char pack[10];

	packetNumber = 1;
	stopPoint = 0;
	eof = FALSE;

	//Odczytanie pierwszego znaku z bufora
	for (i = 0; i <= 6; i++)
	{
		//if(Uart1ReadCheck())
		{
			initSign = uart0GetCh();

			if(initSign == c)
			{
				useCRC = TRUE;
				finalPacketSize = sizeof(dataToSend);
				initalized = TRUE;
				Uart0ClrFifo();
				break;
			}
			else if (initSign == nak)
			{
				useCRC = FALSE;
				finalPacketSize = sizeof(dataToSend) - 1;
				initalized = TRUE;
				Uart0ClrFifo();
				break;
			}

			lcdPuts("initfail");
		}
	}



	if(initalized == FALSE)
	{
		lcdPuts("FAIL");
		return FALSE;
	}


	//Wysylanie pliku
	//lcdClrscr();

	while(failedRetry <= 6)
	{
		XmMakePacket(data);

		uart0SendBuffer(&dataToSend, finalPacketSize);
		initSign = uart0GetCh();

		//intToChar(packetNumber, pack);


		switch(initSign)
		{
		case ack:
			{
				failedRetry = 0;
				lcdPuts("ack\n");
				break;
			}
		case nak:
			{
				lcdPuts("nak\n");
				do
				{
					//Powtarzanie transmisji pakietu
					uart0SendBuffer(&dataToSend, finalPacketSize);
					initSign = uart0GetCh();
					lcdPuts("nak2\n");
					failedRetry++;

				}
				while(initSign != ack && failedRetry <= 6);
				break;
			}
		case can:
			{
				lcdPuts("can\n");
				return FALSE;
				break;
			}
		default:
			{
				do
				{
					uart0SendBuffer(&dataToSend, finalPacketSize);
					initSign = uart0GetCh();
					failedRetry++;

				}
				while(initSign != ack && failedRetry <= 6);
				break;
			}
		}

		if(eof == TRUE)
		{
			break;
		}
	}

	if(failedRetry >= 6)
	{
		initSign = can;
		uart0SendChar(initSign);
		return FALSE;
	}


	do
	{
		initSign = eot;
		uart0SendChar(initSign);
		initSign = uart0GetCh();
	}
	while(initSign != ack);

	return TRUE;
}

void XmMakePacket(tU8* data)
{
	tU32 counter;
	int i;
	XmResetPacket();

	dataToSend.startOfHeader = soh;

	if(packetNumber > 255)
	{
		packetNumber = 1;
	}


	dataToSend.packetNum = packetNumber;
	dataToSend.packetNumCompl = 255 - packetNumber;
	packetNumber++;
	counter = 0;

	//tBool readResult = ReadFile((HANDLE)hFile, &dataToSend.fileData, 128, &counter , NULL);

	//Przekopiowanie danyc do tablicy
	for(i = stopPoint; i < stopPoint + 128; i++)
	{
		if(data[i] == '\0')
		{
			eof = TRUE;
			break;
		}

		dataToSend.fileData[i] = data[i];
		counter++;
	}

	stopPoint += counter;

	if(counter < 128)
	{
		for(i = counter; i < 128; i++)
		{
			dataToSend.fileData[i] = 0x1A;
		}
	}

	if(useCRC)
	{
		tU16 tmp = XmCRC();
		dataToSend.checkSum1 = tmp >> 8;
		dataToSend.checkSum2 = tmp;
	}
	else
	{
		//dataToSend.checkSum1 = 1;
		dataToSend.checkSum1 = XmCheckSum();
	}

}

void XmResetPacket()
{
	int i;
	dataToSend.startOfHeader = 0;
	dataToSend.packetNum = 0;
	dataToSend.packetNumCompl = 0;
	dataToSend.checkSum1 = 0;
	dataToSend.checkSum2 = 0;

	for(i = 0; i < 128; i++)
		dataToSend.fileData[i] = 0;
}

tU16 XmCRC()
{
	crc	= 0x0000;
	int i;
	int j;
	for ( i = 0; i < sizeof(dataToSend.fileData); i++ )
	{
		crc = crc ^ (int)dataToSend.fileData[i] << 8;
		for (j = 0; j < 8; ++j)
		{
			if (crc & 0x8000)
			{
				crc = crc << 1 ^ 0x1021;
			}
			else
			{
				crc = crc << 1;
			}
		}
	}
	return (crc	& 0xFFFF);
}

tU8 XmCheckSum()
{
	tU8 checksum = 0;
	char val[8];
	int i;

	for(i = 0; i < sizeof(dataToSend.fileData); i++)
	{
		checksum += (tU8)dataToSend.fileData[i];
	}

	intToChar(checksum, val);
	lcdPuts(val);

	return checksum;
}
